package com.north.light.libnorthlightbullet.draw;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextUtils;

import com.north.light.libnorthlightbullet.constant.DrawConstant;
import com.north.light.libnorthlightbullet.data.BulletInfo;
import com.north.light.libnorthlightbullet.data.BulletInnerInfo;
import com.north.light.libnorthlightbullet.utils.BulletInfoTrain;
import com.north.light.libnorthlightbullet.utils.BulletPaintUtils;
import com.north.light.libnorthlightbullet.utils.BulletScreenUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * FileName: DrawerHelper
 * Author: lzt
 * Date: 2023/1/14 14:22
 * 绘制工具类
 */
public class DrawerHelper implements DrawerHelperApi {
    //弹幕原数据
    private DrawDataManager sourceData = new DrawDataManager();
    //显示的数据
    private DrawDataManager showData = new DrawDataManager();
    //绘制时间管理
    private DrawTimeHelper drawTimeHelper = new DrawTimeHelper();
    //画笔
    private Paint mDrawPaint = new Paint();

    //移动像素--每一秒
    private static final int COL_MOVE_PX = DrawConstant.CON_DRAW_COL_MOVE_PX;
    private static final int COL_NEXT_PY = DrawConstant.CON_DRAW_COL_MOVE_PY;


    public DrawerHelper() {
        //画笔
        mDrawPaint = new Paint();
        mDrawPaint.setStyle(Paint.Style.FILL);
        mDrawPaint.setStrokeWidth(1);
        mDrawPaint.setAntiAlias(true);
        mDrawPaint.setDither(true);
        mDrawPaint.setTextAlign(Paint.Align.LEFT);
    }

    /**
     * 检查数据--只要符合条件，都放入到显示列表
     */
    @Override
    public void checkDataNormal() {
        //根据当前时间进度，进行加入弹幕
        long currentTime = getCurrentTime();
        boolean change = false;
        for (int i = 0; i < sourceData.size(); i++) {
            BulletInnerInfo bulletInnerInfo = sourceData.get(i);
            if (bulletInnerInfo != null && !TextUtils.isEmpty(bulletInnerInfo.getId()) &&
                    !bulletInnerInfo.isAddToShowList()) {
                long time = bulletInnerInfo.getShowTime();
                if (time <= currentTime) {
                    //能进入的数据，都是没有加载过的数据
                    bulletInnerInfo.setAddToShowList(true);
                    showData.add(bulletInnerInfo);
                    change = true;
                } else {
                    //数据已经排序，若进入该方法，说明后面的数据无需处理
                    break;
                }
            }
        }
        if (change) {
            //排序
            Collections.sort(showData.getBulletList(), new Comparator<BulletInnerInfo>() {
                @Override
                public int compare(BulletInnerInfo o1, BulletInnerInfo o2) {
                    return (int) (o1.getShowTime() - o2.getShowTime());
                }
            });
        }
    }

    /**
     * 检查数据--绘制
     */
    private List<BulletInnerInfo> checkDataOnDraw(int width, int height) {
        if (showData.isEmpty() || width == 0 || height == 0) {
            return new ArrayList<>();
        }
        List<BulletInnerInfo> result = new ArrayList<>();
        //移除没有用的数据
        int size = showData.size();
        for (int i = size - 1; i >= 0; i--) {
            BulletInnerInfo removeCache = showData.get(i);
            if (removeCache.isShown() && removeCache.getPositionX() < -removeCache.getContentWidth()) {
                if (!removeCache.isGoneAfterShow()) {
                    removeCache.setGoneAfterShow(true);
                }
            }
        }
        //获取需要显示的数据集合
        int nextYInterval = BulletScreenUtils.dp2px(COL_NEXT_PY);
        for (int i = 0; i < showData.size(); i++) {
            BulletInnerInfo currentBulletInfo = showData.get(i);
            boolean shown = currentBulletInfo.isShown();
            boolean goneAfterShown = currentBulletInfo.isGoneAfterShow();
            boolean emptyContent = TextUtils.isEmpty(currentBulletInfo.getText());
            if ((shown && goneAfterShown) || emptyContent) {
                continue;
            }
            //至此，是需要显示的数据
            //计算下一个数据显示的高度
            //对于高度的定义：
            // （1）若下一个弹幕的宽度，没有与前面一个弹幕的宽度重合，则高度从0开始
            // （2）不符合（1）的情况，则高度相差一个高度的位置
            float textWidth = BulletPaintUtils.getTextWidth(currentBulletInfo);
            float textHeight = BulletPaintUtils.getTextHeight(currentBulletInfo);

            long currentTime = System.currentTimeMillis();
            boolean needInit = (currentBulletInfo.getShowTime() <= currentTime)
                    && !currentBulletInfo.isShown()
                    && !currentBulletInfo.isGoneAfterShow();

            boolean firstPos = (i == 0);

            if (needInit) {
                //需要初始化
                currentBulletInfo.setShown(true);
                currentBulletInfo.setGoneAfterShow(false);
                String drawText = currentBulletInfo.getText();
                if (!currentBulletInfo.isHadCulPos()) {
                    //x轴自右向左，y轴按照叠加原则去绘制
                    if (!TextUtils.isEmpty(drawText)) {
                        currentBulletInfo.setPositionX(width);
                        currentBulletInfo.setContentWidth(textWidth);
                        currentBulletInfo.setContentHeight(textHeight);

                        float drawY = 0;
                        if (firstPos) {
                            drawY = nextYInterval + textHeight;
                        } else {
                            //获取前面一个数据
                            BulletInnerInfo beforeBulletInfo = showData.get(i - 1);
                            float beforeEndXPos = beforeBulletInfo.getContentWidth() + beforeBulletInfo.getPositionX();
                            if (beforeEndXPos < currentBulletInfo.getPositionX()) {
                                //在前一个后面
                                drawY = nextYInterval + textHeight;
                            } else {
                                //在前一个下面--判断是否超过控件高度
                                float beforeEndYPos = beforeBulletInfo.getPositionY();
                                float targetY = beforeEndYPos + nextYInterval + textHeight;
                                if (targetY < height) {
                                    drawY = targetY;
                                } else {
                                    drawY = nextYInterval + textHeight;
                                }
                            }
                        }
                        float trainDrawY = drawY;
                        currentBulletInfo.setPositionY(trainDrawY);
                    }
                    currentBulletInfo.setHadCulPos(true);
                }
                showData.set(i, currentBulletInfo);
            }

            if (currentBulletInfo.isShown() && !currentBulletInfo.isGoneAfterShow()) {
                result.add(currentBulletInfo);
            }
        }
        return result;
    }


    //弹幕数据相关------------------------------------------------------------

    @Override
    public void addBulletSingle(BulletInfo data) {
        drawTimeHelper.start();
        sourceData.addBulletSingle(data);
    }

    @Override
    public void addBulletList(List<BulletInfo> data) {
        drawTimeHelper.start();
        sourceData.addBulletList(data);
    }

    @Override
    public void setBulletList(List<BulletInfo> data) {
        drawTimeHelper.start();
        sourceData.setBulletList(data);
    }

    @Override
    public List<BulletInnerInfo> getBulletList() {
        return sourceData.getBulletList();
    }

    //操作相关------------------------------------------------------------

    @Override
    public void draw(Canvas canvas, int parentWidth, int parentHeight,
                     DrawerStatus drawerStatus,
                     DrawerHelperDrawingEvent listener) {

        //检查数据，绘制
        List<BulletInnerInfo> drawList = checkDataOnDraw(parentWidth, parentHeight);

        if (drawList.size() != 0) {
            for (int i = 0; i < drawList.size(); i++) {
                BulletInnerInfo cache = drawList.get(i);
                if (!TextUtils.isEmpty(cache.getText())) {

                    mDrawPaint.setStyle(Paint.Style.FILL);
                    mDrawPaint.setTextSize(BulletScreenUtils.dp2px(cache.getTextSize()));
                    mDrawPaint.setTypeface((cache.isBold()) ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
                    mDrawPaint.setColor(cache.getTextColor());

                    //若显示，则调用canvas绘制，否则不绘制，只改变参数
                    if (drawerStatus.isShow() && drawerStatus.isWindowFocus()) {
                        //绘制背景回调
                        if (listener != null) {
                            float nextYInterval = BulletPaintUtils.getTextDescent(cache);
                            float left = cache.getPositionX();
                            float top = cache.getPositionY() - cache.getContentHeight() + nextYInterval;
                            float right = cache.getPositionX() + cache.getContentWidth();
                            float bottom = cache.getPositionY() + nextYInterval;
                            listener.drawBg(BulletInfoTrain.getInstance().trainOuter(cache), canvas, left, top, right, bottom);
                        }
                        canvas.drawText(cache.getText(), cache.getPositionX(), cache.getPositionY(), mDrawPaint);
                    }

                    //判断是否暂停，从而进行数据的位置
                    if (!drawerStatus.isPausing()) {
                        cache.setPositionX(cache.getPositionX() - COL_MOVE_PX);
                    }

                    drawList.set(i, cache);
                }
            }
        }
    }

    @Override
    public void clearAllData() {
        sourceData.clear();
        showData.clear();
    }

    @Override
    public void clearShowData() {
        showData.clear();
    }

    @Override
    public void timer(long interval) {
        drawTimeHelper.update(interval);
    }

    @Override
    public void resetTime() {
        drawTimeHelper.reset();
        drawTimeHelper.start();
    }

    @Override
    public long getCurrentTime() {
        return drawTimeHelper.get();
    }

    @Override
    public void clearScreen() {
        //清屏操作
        long currentTime = System.currentTimeMillis();
        for (int i = 0; i < showData.size(); i++) {
            BulletInnerInfo cache = showData.get(i);
            if (cache.getShowTime() <= currentTime) {
                cache.setShown(true);
                cache.setGoneAfterShow(true);
                cache.setHadCulPos(false);
                cache.setAddToShowList(false);
                showData.set(i, cache);
            }
        }
    }

    @Override
    public void seekTo(long progress) {
        showData.getBulletList().clear();
        long currentTime = getCurrentTime();
        for (int i = 0; i < sourceData.size(); i++) {
            BulletInnerInfo cache = sourceData.get(i);
            if (cache.getShowTime() <= currentTime) {
                cache.setShown(false);
                cache.setGoneAfterShow(false);
                cache.setHadCulPos(false);
                cache.setAddToShowList(false);
            }
        }
        drawTimeHelper.setProgress(progress);
    }


}
